<?php

namespace app\api\controller;

use app\common\controller\Frontend;
use app\common\model\enneagram\Results;
use app\common\model\Order as ModelOrder;
use ba\PayLib;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\QROptions;
use think\facade\Db;
use think\facade\Validate;
use Throwable;
use Yansongda\Pay\Pay;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Log;

class Order extends Frontend
{
    // 无需登录的方法
    protected array $noNeedLogin = ['*'];

    // 无需鉴权的方法
    protected array $noNeedPermission = ['*'];


    public function initialize(): void
    {
        parent::initialize();
    }

    /**
     * 获取微信OAuth授权URL（静默snsapi_base）
     * 前端在微信内置浏览器环境下调用，跳转后回到callback以获取openid
     */
    public function wechatAuthUrl()
    {
        $redirect = $this->request->param('redirect', $this->request->url(true));
        $state = $this->request->param('state', 'STATE');

        $config = Config::get('wechat.official_account');
        Log::write('微信配置新福克斯teconfig ' . json_encode($config));
        if (empty($config['app_id']) || empty($config['secret'])) {
            return $this->error('微信公众号配置缺失');
        }

        // 构造授权URL：snsapi_base 静默授权，获取openid
        $appid = $config['app_id'];
        $scope = 'snsapi_base';
        // 回跳到后端回调以生成临时 openid_token 并携带回前端
        $scheme = $this->request->scheme();
        $host = $this->request->host();
        $callbackUrl = $scheme . '://' . $host . '/api/order/wechatAuthCallback?redirect=' . urlencode($redirect);
        $authUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$appid}&redirect_uri=" . urlencode($callbackUrl) . "&response_type=code&scope={$scope}&state={$state}#wechat_redirect";

        return $this->success('授权地址', ['auth_url' => $authUrl]);
    }

    /**
     * 微信OAuth回调：根据code换取openid
     * 文档：https://developers.weixin.qq.com/doc/service/guide/h5/auth.html
     */
    public function wechatAuthCallback()
    {
        $code = $this->request->param('code');
        $redirect = $this->request->param('redirect', '');
        if (empty($code)) {
            return $this->error('缺少授权code');
        }

        $config = Config::get('wechat.official_account');
        if (empty($config['app_id']) || empty($config['secret'])) {
            return $this->error('微信公众号配置缺失');
        }

        try {
            // 直接调用微信接口换取openid，避免依赖不存在的类
            $appid = $config['app_id'];
            $secret = $config['secret'];

            $client = new \GuzzleHttp\Client(['timeout' => 5.0]);
            $resp = $client->get('https://api.weixin.qq.com/sns/oauth2/access_token', [
                'query' => [
                    'appid' => $appid,
                    'secret' => $secret,
                    'code' => $code,
                    'grant_type' => 'authorization_code',
                ],
            ]);

            $data = json_decode((string)$resp->getBody(), true);
            if (isset($data['errcode']) && $data['errcode'] !== 0) {
                return $this->error('微信返回错误: ' . ($data['errmsg'] ?? '未知错误'));
            }

            $openid = $data['openid'] ?? '';
            if (empty($openid)) {
                return $this->error('未获取到openid');
            }
            // 使用缓存（如Redis）生成临时token并保存openid（有效期10分钟）
            $token = 'wx_openid_' . bin2hex(random_bytes(16));
            Cache::set($token, $openid, 600);

            // 如果传入了回跳地址，携带 openid_token 回到前端页面
            if (!empty($redirect)) {
                $separator = strpos($redirect, '?') !== false ? '&' : '?';
                $final = $redirect . $separator . 'openid_token=' . urlencode($token);
                header('Location: ' . $final);
                exit;
            }
        } catch (\Throwable $e) {
            \think\facade\Log::error('获取openid异常: ' . $e->getMessage());
            return $this->error('获取openid异常: ' . $e->getMessage());
        }
        // 默认返回 JSON，前端也可选择读取并继续流程
        return $this->success('授权成功', ['openid_token' => $token, 'expire' => 600]);
    }
    /**
     * 创建订单
     * @throws Throwable
     */
    public function create()
    {
        // 验证参数
        $validate = Validate::rule([
            'id' => 'require|number',
            'amount' => 'require',
        ]);

        $params = $this->request->post();
        if (!$validate->check($params)) {
            $this->error($validate->getError());
        }

        $resultId = $params['id'];

        // 检查测试是否存在且未完成
        $result = Results::where(['id' => $resultId])->findOrEmpty();
        if ($result->isEmpty()) {
            return $this->error('报告不存在！');
        }
        $price = get_sys_config('enneagram_test_price');
        if (empty($price)) {
            $this->error('价格未设置！');
        }
        $formattedPrice = number_format(floatval($price), 2, '.', '');
        if (bccomp($formattedPrice, '0.00', 2) <= 0) {
            $this->error('测试价格错误！必需大于0！');
        }
        $amount = $params['amount'];
        $formattedAmount = number_format(floatval($amount), 2, '.', '');
        // 使用bccomp进行精确比较，精度为1位小数
        if (bccomp($formattedPrice, $formattedAmount, 2) !== 0) {
            $this->error('传入的价格无效！');
        }

        $userId = $this->auth?->id;
        $wheres = [
            'result_id' => $result->id,
            'status' => 1,
            'pay_status' => ModelOrder::PAY_STATUS_UNPAY
        ];
        if ($userId) {
            $wheres['user_id'] = $userId;
        }
        // 检查是否已有未支付订单
        $existingOrder = ModelOrder::where($wheres)->findOrEmpty();
        if (!$existingOrder->isEmpty()) {
            return  $this->success('已有未支付的订单！', ['order_id' => $existingOrder->id]);
        }

        // 使用事务确保订单创建原子性
        Db::startTrans();
        try {
            $order = new ModelOrder();
            $order->order_no = $this->generateUniqueOrderNo();
            $order->user_id = $this->auth?->id ?: 0;
            $order->result_id = $result->id;
            $order->amount = $formattedPrice;
            $order->pay_status = ModelOrder::PAY_STATUS_UNPAY;
            $order->acquisition_type = ModelOrder::ACQUISITION_TYPE_PAYMENT;
            // $order->payment_method = $payment_method;//这里不记录，支付成功后再记录
            $order->status = 1;
            $order->save();

            // 更新报告表的order_id字段
            $result->order_id = $order->id;
            $result->save();

            Db::commit();
        } catch (Throwable $e) {
            Db::rollback();
            $this->error('订单创建失败: ' . $e->getMessage());
        }
        $this->success('订单创建成功', ['order_id' => $order->id]);
    }

    /**
     * 生成唯一订单号
     * @return string
     */
    private function generateUniqueOrderNo(): string
    {
        $maxAttempts = 10; // 最大尝试次数
        $attempts = 0;
        $user_id = $this->auth?->id;
        do {
            // 生成订单号格式：EN + 年月日时分秒 + 5位随机数 + 4位用户ID
            $orderNo = 'EN' . date('YmdHis') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT) . ($user_id ? str_pad($user_id % 10000, 4, '0', STR_PAD_LEFT) : '0000');

            // 检查订单号是否已存在
            $exists = ModelOrder::where('order_no', $orderNo)->findOrEmpty();

            // 如果不存在，返回这个订单号
            if ($exists->isEmpty()) {
                return $orderNo;
            }
            // 增加尝试次数并短暂延迟，避免生成过于相似的订单号
            $attempts++;
            usleep(100000); // 延迟0.1秒

        } while ($attempts < $maxAttempts);

        // 如果多次尝试后仍无法生成唯一订单号，使用更复杂的方式
        return 'EN' . date('YmdHis')
            . str_pad(mt_rand(1, 999999), 6, '0', STR_PAD_LEFT)
            . substr(md5(uniqid(mt_rand(), true)), 0, 6);
    }

    /**
     * 检查报告支付状态
     */
    public function checkPayStatus()
    {
        // 验证参数
        $validate = Validate::rule([
            'result_id' => 'require|number',
        ]);

        $params = $this->request->post();
        if (!$validate->check($params)) {
            $this->error($validate->getError());
        }

        $resultId = $params['result_id'];
        $result = Results::field('id,pay_status')->findOrEmpty($resultId);
        if ($result->isEmpty()) $this->error('报告不存在！');

        $this->success('支付状态', ['paid' =>  $result->pay_status == Results::PAY_STATUS_PAID ? 'Y' : 'N']);
    }

    /**
     * 创建兑换码订单
     * @throws Throwable
     */
    public function createRedemptionOrder()
    {
        // 验证参数
        $validate = Validate::rule([
            'id' => 'require|number',
        ]);

        $params = $this->request->post();
        if (!$validate->check($params)) {
            $this->error($validate->getError());
        }

        $resultId = $params['id'];

        // 检查测试是否存在
        $result = Results::where(['id' => $resultId])->findOrEmpty();
        if ($result->isEmpty()) {
            return $this->error('报告不存在！');
        }

        // 检查报告是否已经支付
        if ($result->pay_status == Results::PAY_STATUS_PAID) {
            return $this->error('报告已经支付，无需重复创建订单！');
        }

        $price = get_sys_config('enneagram_test_price');
        if (empty($price)) {
            $this->error('价格未设置！');
        }
        $formattedPrice = number_format(floatval($price), 2, '.', '');
        if (bccomp($formattedPrice, '0.00', 2) <= 0) {
            $this->error('测试价格错误！必需大于0！');
        }

        $userId = $this->auth?->id;
        $wheres = [
            'result_id' => $result->id,
            'status' => 1,
            'acquisition_type' => ModelOrder::ACQUISITION_TYPE_REDEMPTION
        ];
        if ($userId) {
            $wheres['user_id'] = $userId;
        }

        // 检查是否已有兑换码订单
        $existingOrder = ModelOrder::where($wheres)->findOrEmpty();
        if (!$existingOrder->isEmpty()) {
            return $this->success('已有兑换码订单！', ['order_id' => $existingOrder->id]);
        }

        // 使用事务确保订单创建原子性
        Db::startTrans();
        try {
            $order = new ModelOrder();
            $order->order_no = $this->generateUniqueOrderNo();
            $order->user_id = $this->auth?->id ?: 0;
            $order->result_id = $result->id;
            $order->amount = 0;
            $order->pay_status = ModelOrder::PAY_STATUS_PAID; // 兑换码订单默认已支付
            $order->acquisition_type = ModelOrder::ACQUISITION_TYPE_REDEMPTION; // 兑换码获取
            $order->payment_method = ModelOrder::PAYMENT_METHOD_REDEMPTION; // 支付方式为兑换码
            $order->status = 1;
            $order->save();

            // 更新报告表的order_id字段
            $result->order_id = $order->id;
            $result->save();

            Db::commit();
        } catch (Throwable $e) {
            Db::rollback();
            $this->error('兑换码订单创建失败: ' . $e->getMessage());
        }

        $this->success('兑换码订单创建成功', ['order_id' => $order->id]);
    }



    /**
     * 发起支付
     */
    public function payment()
    {
        // 自动判断客户端类型
        // $client = $this->detectClientType();
        // halt($client, 'mobile', $this->request->isMobile());
        // 验证参数
        $validate = Validate::rule([
            'order_id' => 'require|number',
            'payment_method' => 'require|in:wechat,alipay', //'selected_option' => 'require|in:A,B,a,b'
        ]);

        $userId = $this->auth?->id ?: 0;
        $params = $this->request->post();
        if (!$validate->check($params)) {
            $this->error($validate->getError());
        }
        $orderId = $params['order_id'];
        $order = ModelOrder::findOrEmpty($orderId);
        if ($order->isEmpty()) {
            $this->error('订单不存在');
        }
        // 验证订单所有者
        if ($userId && $order->user_id != $userId) {
            $this->error('无权操作此报告');
        }
        // 检查订单支付状态
        if ($order->pay_status != ModelOrder::PAY_STATUS_UNPAY) {
            $this->error('订单支付状态异常!');
        }
        // 检查订单哥status状态
        if ($order->status != 1) {
            $this->error('订单状态异常!');
        }
        $price = get_sys_config('enneagram_test_price');
        if (empty($price)) {
            $this->error('价格未设置！');
        }
        $formattedPrice = number_format(floatval($price), 2, '.', '');
        if (bccomp($formattedPrice, '0.00', 2) <= 0) {
            $this->error('测试价格错误！必需大于0！');
        }
        // 根据支付方式生成支付参数
        $paymentParams = $this->generatePaymentParams($order, $params['payment_method']);

        $this->success('支付参数', [
            'order_id' => $order->id,
            // 'qr_code' => $paymentParams['qr_code'],
            // 'payment_url' => $paymentParams['payment_url'] ?? null,
            'paymentParams' => $paymentParams
        ]);
    }


    /**
     * 生成支付参数
     * @param ModelOrder $modelOrder 订单模型
     * @param string $payment_method 支付方式：wechat或alipay
     * @return array 支付参数
     */
    private function generatePaymentParams(ModelOrder $modelOrder, $payment_method)
    {
        // 配置支付参数
        Pay::config(PayLib::getConfig());

        try {
            $paymentHandlers = [
                'wechat' => 'generateWechatPaymentParams',
                'alipay' => 'generateAlipayPaymentParams'
            ];

            // 检查支付方式是否支持
            if (!isset($paymentHandlers[$payment_method])) {
                throw new \Exception('不支持的支付方式');
            }
            // 动态调用对应的处理方法
            $handler = $paymentHandlers[$payment_method];
            return $this->{$handler}($modelOrder);
        } catch (Throwable $e) {
            // 记录错误日志
            \think\facade\Log::error('生成支付参数失败: ' . $e->getMessage());
            throw new \Exception('生成支付参数失败: ' . $e->getMessage());
        }
    }

    /**
     * 生成微信支付参数
     * @param ModelOrder $modelOrder 订单模型
     * @return array 支付参数
     */
    private function generateWechatPaymentParams(ModelOrder $modelOrder)
    {
        // 计算支付金额（单位：分）
        $amount = intval(bcmul($modelOrder->amount, 100));

        // 基础订单信息
        $order = [
            'out_trade_no' => $modelOrder->order_no,
            'description' => '九型人格-测试 ' . $modelOrder->result_id,
            'amount' => [
                'total' => $amount,
            ],
        ];

        // 临时用，后续根据客户端类型判断是否需要openid
        $result = Pay::wechat(PayLib::getConfig())->scan($order);
        return [
            'type' => 'scan',
            'code_url' => $result->code_url,
            'qr_code' => $this->generateQrCode($result->code_url),
            'payment_method' => 'wechat'
        ];

        // 自动判断客户端类型
        // $client = $this->detectClientType();
        // switch ($client) {
        //     case 'wechat': // 微信内置浏览器
        //         // 需要openid参数
        //         $openid = $this->request->param('openid');
        //         if (empty($openid)) {
        //             $openidToken = $this->request->param('openid_token');
        //             if (!empty($openidToken)) {
        //                 $openid = (string)Cache::get($openidToken, '');
        //             }
        //         }
        //         if (empty($openid)) {
        //             throw new \Exception('微信支付需要提供openid');
        //         }

        //         $order['payer'] = [
        //             'openid' => $openid
        //         ];

        //         $result = Pay::wechat(PayLib::getConfig())->mp($order);
        //         return [
        //             'type' => 'jsapi',
        //             'payment_data' => $result,
        //             'payment_method' => 'wechat'
        //         ];

        //     case 'web': // 网页端
        //         // H5支付，适用于手机浏览器
        //         if ($this->request->isMobile()) {
        //             $result = Pay::wechat(PayLib::getConfig())->h5($order);
        //             return [
        //                 'type' => 'h5',
        //                 'payment_url' => $result->h5_url,
        //                 'payment_method' => 'wechat'
        //             ];
        //         }

        //         // PC端使用扫码支付
        //         $result = Pay::wechat(PayLib::getConfig())->scan($order);
        //         return [
        //             'type' => 'scan',
        //             'code_url' => $result->code_url,
        //             'qr_code' => $this->generateQrCode($result->code_url),
        //             'payment_method' => 'wechat'
        //         ];

        //     case 'mp': // 微信小程序
        //         // 需要openid参数
        //         $openid = $this->request->param('openid');
        //         if (empty($openid)) {
        //             throw new \Exception('使用小程序支付需要提供openid');
        //         }

        //         $order['payer'] = [
        //             'openid' => $openid
        //         ];

        //         $result = Pay::wechat(PayLib::getConfig())->mini($order);
        //         return [
        //             'type' => 'mini',
        //             'payment_data' => $result,
        //             'payment_method' => 'wechat'
        //         ];

        //     case 'app': // APP支付
        //         $result = Pay::wechat(PayLib::getConfig())->app($order);
        //         return [
        //             'type' => 'app',
        //             'payment_data' => $result,
        //             'payment_method' => 'wechat'
        //         ];

        //     default:
        //         throw new \Exception('不支持的客户端类型');
        // }
    }
    /**
     * 生成二维码
     * @param string $content 二维码内容
     * @return string base64编码的二维码图片
     */
    private function generateQrCode(string $content): string
    {
        $options = [
            'version'         => 5,  // 二维码版本(1-40)
            'outputType'      => 'png',
            'eccLevel'        => 2,  // 纠错级别：0=L(7%), 1=M(15%), 2=Q(25%), 3=H(30%)
            'scale'           => 5,    // 缩放比例
            'imageBase64'     => true, // 直接返回base64编码
            'moduleValues'    => [
                // 颜色设置
                1536 => [0, 0, 0],    // 前景色(黑)
                6    => [255, 255, 255], // 背景色(白)
            ],
        ];

        $qrCode = new QRCode(new QROptions($options));
        return $qrCode->render($content);
    }
    /**
     * 生成支付宝支付参数
     * @param ModelOrder $modelOrder 订单模型
     * @return array 支付参数
     */
    private function generateAlipayPaymentParams(ModelOrder $modelOrder)
    {
        // 支付宝特有参数
        $alipayOrder = [
            'out_trade_no' => $modelOrder->order_no,
            'subject' => '九型人格-测试 ' . $modelOrder->result_id,
            'total_amount' => $modelOrder->amount, // 支付宝使用元为单位
            // 'quit_url' => 'https://yansongda.cn',//
        ];

        // 自动判断客户端类型
        $client = $this->detectClientType();

        switch ($client) {
            case 'web': // 网页端
                // 手机端使用手机网站支付
                if ($this->request->isMobile()) {
                    $result = Pay::alipay(PayLib::getConfig())->h5($alipayOrder);
                    return [
                        'type' => 'h5',
                        'payment_html' => $result,
                        'payment_method' => 'alipay'
                    ];
                }

                //  //支付宝扫码支付
                //  $result = Pay::alipay(PayLib::getConfig())->scan($alipayOrder);
                //  return [
                //      'type' => 'scan',
                //      'code_url' => $result->qr_code,
                //      'qr_code' => $this->generateQrCode($result->qr_code),
                //      'payment_method' => 'alipay'
                //  ];
                // PC端使用电脑网站支付
                $result = Pay::alipay(PayLib::getConfig())->web($alipayOrder);
                return [
                    'type' => 'web',
                    'payment_html' => $result,
                    'payment_method' => 'alipay'
                ];

            case 'app': // APP支付
                $result = Pay::alipay(PayLib::getConfig())->app($alipayOrder);
                return [
                    'type' => 'app',
                    'payment_data' => $result,
                    'payment_method' => 'alipay'
                ];
            default:
                throw new \Exception('不支持的客户端类型');
        }
    }


    /**
     * 自动检测客户端类型
     * @return string 客户端类型：web, mp, app, wechat
     */
    private function detectClientType()
    {
        // 获取后端可见的信息
        $userAgent = strtolower($this->request->header('user-agent', ''));
        $referer = strtolower($this->request->header('referer', ''));

        // 接收前端传递的额外信息
        $client_type = $this->request->param('client_type', '');

        // 记录信息用于审计
        \think\facade\Log::info('支付客户端检测', [
            'ua' => $userAgent,
            'referer' => $referer,
            'ip' => $this->request->ip(),
            'client_type' => $client_type,
        ]);

        // 更严格的微信环境检测
        $isWechat = strpos($userAgent, 'micromessenger') !== false
            || strpos($userAgent, 'wechat/') !== false;

        if ($isWechat) {
            // 增强版小程序检测
            if (
                strpos($referer, 'servicewechat.com') !== false ||
                strpos($userAgent, 'miniprogram') !== false ||
                strpos($userAgent, 'miniprogramenv') !== false ||
                $this->request->header('from') === 'wxapp' ||
                $this->request->header('x-wx-source') !== null
            ) {
                return 'mp';
            }
            return 'wechat';
        }

        // 更精确的APP检测 - 使用更严格的标记
        $appMarkers = [
            'okhttp',
            'dalvik', // Android特有
            'react-native',
            'flutter', // 跨平台框架
            'myapp/' // 自定义APP标记(可替换为实际APP标识)
        ];

        $mobileMarkers = [
            'android',
            'iphone os',
            'ios'
        ];

        // 先检查明确的APP标记
        foreach ($appMarkers as $marker) {
            if (stripos($userAgent, $marker) !== false) {
                return 'app';
            }
        }

        // 客户端类型参数安全校验 - 增加额外验证
        $clientParam = $this->request->param('client_type');
        if (in_array($clientParam, ['mp', 'app', 'wechat'])) {
            // 如果声明为APP，检查是否至少有移动设备标记
            if ($clientParam === 'app') {
                $hasMobileMarker = false;
                foreach ($mobileMarkers as $marker) {
                    if (stripos($userAgent, $marker) !== false) {
                        $hasMobileMarker = true;
                        break;
                    }
                }

                if (!$hasMobileMarker) {
                    \think\facade\Log::warning('可疑的APP客户端声明', [
                        'ua' => $userAgent,
                        'ip' => $this->request->ip()
                    ]);
                    // 可以选择拒绝或降级到web
                    return 'web';
                }
            }

            return $clientParam;
        }

        // 默认为web
        return 'web';
    }
}
